#include "DES.h"

int key[16][48];

void keyBuild(int *keychar) {
	int i, j;
	int movebit[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
	int midkey2[56];
	int midkey[64];

	StrtoBin(midkey, keychar);

	for (i = 0; i < 56; i++) {
		midkey2[i] = midkey[PC1[i] - 1];
	}

	for (i = 0; i < 16; i++) {
		keyCreate(midkey2, movebit[i], i);
	}
}

void StrtoBin(int *midkey, int *keychar) {
	int trans[8], i, j, k, n;

	n = 0;

	for (i = 0; i < 8; i++) {
		j = 0;

		while (keychar[i] != 0) {
			trans[j] = keychar[i] % 2;
			keychar[i] = keychar[i] / 2;
			j++;
		}

		for (k = j; k < 8; k++) {
			trans[k] = 0;
		}

		for (k = 0; k < 8; k++) {
			midkey[n++] = trans[7 - k];
		}
	}
}

void keyCreate(int *midkey2, int movebit, int n) {
	int i, temp[4];

	temp[0] = midkey2[0];
	temp[1] = midkey2[1];
	temp[2] = midkey2[28];
	temp[3] = midkey2[29];

	if (movebit == 2) {
		for (i = 0; i < 26; i++) {
			midkey2[i] = midkey2[i + 2];
			midkey2[i + 28] = midkey2[i + 30];
		}

		midkey2[26] = temp[0];
		midkey2[27] = temp[1];
		midkey2[54] = temp[2];
		midkey2[55] = temp[3];
	} else {
		for (i = 0; i < 27; i++) {
			midkey2[i] = midkey2[i + 1];
			midkey2[i + 28] = midkey2[i + 29];
		}

		midkey2[27] = temp[0];
		midkey2[55] = temp[2];
	}

	for (i = 0; i < 48; i++) {
		key[n][i] = midkey2[PC2[i] - 1];
	}
}

void EncodeData(int *lData, int *rData, int *str) {
	int i, j, temp[8], lint, rint;
	int data[64];

	lint = 0, rint = 0;

	for (i = 0; i < 4; i++) {
		j = 0;

		while (str[i] != 0) {
			temp[j] = str[i] % 2;
			str[i] = str[i] / 2;
			j++;
		}

		while (j < 8) {
			temp[j++] = 0;
		}

		for (j = 0; j < 8; j++) {
			lData[lint++] = temp[7 - j];
		}

		j = 0;

		while (str[i + 4] != 0) {
			temp[j] = str[i + 4] % 2;
			str[i + 4] = str[i + 4] / 2;
			j++;
		}

		while (j < 8) {
			temp[j++] = 0;
		}

		for (j = 0; j < 8; j++) {
			rData[rint++] = temp[7 - j];
		}
	}

	for (i = 0; i < 32; i++) {
		data[i] = lData[i];
		data[i + 32] = rData[i];
	}

	for (i = 0; i < 32; i++) {
		lData[i] = data[IP1[i] - 1];
		rData[i] = data[IP1[i + 32] - 1];
	}
}

void F(int *rData, int *key) {
	int i, rDataP[48];

	Expand(rData, rDataP);

	for (i = 0; i < 48; i++) {
		rDataP[i] = rDataP[i] ^ key[i];
	}

	ExchangeS(rDataP, rData);

	ExchangeP(rData);

}

void Expand(int *rData, int *rDataP) {
	int i;

	for (i = 0; i < 48; i++) {
		rDataP[i] = rData[Ex[i] - 1];
	}
}

void ExchangeS(int *rDataP, int *rData) {
	int i, n, linex, liney;

	linex = liney = 0;

	for (i = 0; i < 48; i += 6) {
		n = i / 6;
		linex = (rDataP[i] << 1) + rDataP[i + 5];
		liney = (rDataP[i + 1] << 3) + (rDataP[i + 2] << 2)
				+ (rDataP[i + 3] << 1) + rDataP[i + 4];

		FillBin(rData, n, s[n][linex][liney]);
	}
}

void ExchangeP(int *rData) {
	int i, temp[32];

	for (i = 0; i < 32; i++) {
		temp[i] = rData[i];
	}

	for (i = 0; i < 32; i++) {
		rData[i] = temp[P[i] - 1];
	}
}

void FillBin(int *rData, int n, int s) {
	int temp[4], i;

	for (i = 0; i < 4; i++) {
		temp[i] = s % 2;
		s = s / 2;
	}

	for (i = 0; i < 4; i++) {
		rData[n * 4 + i] = temp[3 - i];
	}
}

void DecodeData(int *str, int *lData, int *rData) {
	int i;
	int a, b;
	int data[64];

	a = 0, b = 0;

	for (i = 0; i < 32; i++) {
		data[i] = lData[i];
		data[i + 32] = rData[i];
	}

	for (i = 0; i < 32; i++) {
		lData[i] = data[IP2[i] - 1];
		rData[i] = data[IP2[i + 32] - 1];
	}

	for (i = 0; i < 32; i++) {
		a = (lData[i] & 0x1) + (a << 1);
		b = (rData[i] & 0x1) + (b << 1);
		if ((i + 1) % 8 == 0) {
			str[i / 8] = a;
			a = 0;
			str[i / 8 + 4] = b;
			b = 0;
		}
	}
}

void Encode(int *str, int *keychar) {
	int lData[32], rData[32], temp[32], rDataP[48];
	int i, j;

	keyBuild(keychar);

	EncodeData(lData, rData, str);

	for (i = 0; i < 16; i++) {
		for (j = 0; j < 32; j++) {
			temp[j] = rData[j];
		}

		F(rData, key[i]);

		for (j = 0; j < 32; j++) {
			rData[j] = rData[j] ^ lData[j];
		}

		for (j = 0; j < 32; j++) {
			lData[j] = temp[j];
		}
	}

	DecodeData(str, rData, lData);
}
